package de.szut.dqi10.brailletouchscreenreader.display;

import java.util.LinkedList;

import android.app.Activity;
import android.content.Context;
import android.os.Vibrator;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

import de.szut.dqi10.brailletouchscreenreader.braillechar.BrailleChar;

/**
 * OnTouchListener for the BrailleView
 * @author Marco Jedzig, Simon Grafenhorst, Felix Pusch
 *
 */
public class BrailleTouchListener implements OnTouchListener {

	private int vibrateMode;
	private int scaleX;
	private int scaleY;
	private boolean autoNextChar;
	private LinkedList<Integer> touchedButtons;

	private boolean vibrating = false;
	private int lastButton;
	private int vibrateTime = 100;

	private BrailleChar brailleChar;
	private int buttonHeight;
	private int buttonWidth;

	private String TAG = "BrailleTouchListener";

	/**
	 * Constructor for the BrailleTouchListener. It sets the brailleChar, the
	 * vibrateMode and the borders to each side of the buttons
	 * 
	 * @param brailleChar
	 *            The first BrailleChar to display
	 * 
	 * @param vibrateMode
	 *            The current vibration mode
	 * 
	 * @param scaleX
	 *            The horizontal scale of the buttons
	 * 
	 * @param scaleY
	 *            The vertical scale of the buttons
	 * 
	 * @param borderX
	 *            The X-Border of each button to each side
	 * 
	 * @param borderY
	 *            The Y-Border of each button to each side
	 */
	public BrailleTouchListener(BrailleChar brailleChar, int vibrateMode,
			int scaleX, int scaleY, boolean autoNextChar) {
		this.brailleChar = brailleChar;
		this.vibrateMode = vibrateMode;
		this.scaleX = scaleX;
		this.scaleY = scaleY;
		this.autoNextChar = autoNextChar;
		touchedButtons = new LinkedList<Integer>();
		lastButton = 7;
	}

	/**
	 * The onTouch method to give vibration feedback and to open the menu.
	 * Calculates the button which was pressed and shifts the brailleChar to the
	 * right until the corresponding bit is the last one (ASR until last bit
	 * corresponds to pressed button). Then checks with %2 if the last bit is
	 * set or not and vibrates if it is. Also checks whether the position of the
	 * touchEvent is in the area of the button or outside.
	 */
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		buttonHeight = (int) (v.getScaleY() * v.getHeight() / 3);
		buttonWidth = (int) (v.getScaleX() * v.getWidth() / 2);
		int borderX = ((int) (float) buttonWidth - buttonWidth * scaleX
				/ 100) / 2;
		int borderY = ((int) (float) buttonHeight - buttonHeight * scaleY
				/ 100) / 2;
		int activatedButton = (int) (event.getRawY() / buttonHeight)
				+ (int) (event.getRawX() / buttonWidth) * 3;
		Vibrator vibrator = (Vibrator) ((Activity) v.getContext())
				.getSystemService(Context.VIBRATOR_SERVICE);
		if (((int) brailleChar.getBrailleChar() >> activatedButton) % 2 == 1
				&& (event.getRawX() % buttonWidth) > borderX
				&& (event.getRawX() % buttonWidth) < (buttonWidth - borderX)
				&& (event.getRawY() % buttonHeight) > borderY
				&& (event.getRawY() % buttonHeight) < buttonHeight - borderY) {

			if (vibrateMode == 1) {
				if (lastButton != activatedButton) {
					lastButton = activatedButton;
					vibrator.vibrate(vibrateTime);
					vibrating = true;
				}
			} else if (!vibrating) {
				vibrator.vibrate(100000);
				vibrating = true;
			}
			Log.i(TAG, "Vibration activated, vibrate mode " + vibrateMode);
		} else if (vibrating) {
			lastButton = 7;
			vibrator.cancel();
			vibrating = false;
			Log.i(TAG, "Vibration canceled (touchEvent not on activated button");
		}

		if (event.getActionMasked() == MotionEvent.ACTION_UP) {
			lastButton = 7;
			if (vibrating) {
				vibrator.cancel();
				vibrator.vibrate(1);
				vibrator.cancel();
				vibrating = false;
				Log.i(TAG, "Vibration stopped (ACTION_UP touchEvent");
			}
			if (touchedButtons.size() == 6 && autoNextChar) {
				Log.i(TAG, "Automoving to next Character");
				((BrailleMainActivity) v.getContext()).displayNextBrailleChar();
				touchedButtons.clear();
			}
		}
		if (event.getPointerCount() > 1) {
			Log.i(TAG, "Multitouch event; trying to open settings");
			((Activity) v.getContext()).openOptionsMenu();
		} else if (!touchedButtons.contains(activatedButton)
				&& event.getActionMasked() != MotionEvent.ACTION_UP) {
			touchedButtons.add(activatedButton);
		}

		return true;
	}

	/**
	 * Sets the size of the buttons
	 * 
	 * @param scaleX
	 *            The horizontal scale of the button
	 * 
	 * @param scaleY
	 *            The vertical scale of the button
	 */
	public void setButtonSize(int scaleX, int scaleY) {
		this.scaleX = scaleX;
		this.scaleY = scaleY;
	}

	/**
	 * Sets the current vibrate mode
	 * 
	 * @param vibrateMode
	 *            The current vibration mode
	 */
	public void setVibrateMode(int vibrateMode) {
		this.vibrateMode = vibrateMode;
	}

	/**
	 * Sets the vibrate time for vibrateMode 1
	 * 
	 * @param vibrateTime
	 *            The Time in ms the phone vibrates on each button
	 */
	public void setVibrateTime(int vibrateTime) {
		this.vibrateTime = vibrateTime;
	}

	/**
	 * Sets the autoNextChar variable which determines if the next char is
	 * displayed automatically as soon as every button is touched once
	 * 
	 * @param autoNextChar
	 *            The state of the autoNextChar variable
	 */
	public void setAutoNextChar(boolean autoNextChar) {
		this.autoNextChar = autoNextChar;
	}

	/**
	 * Sets the brailleChar to display
	 * 
	 * @param brailleChar
	 *            The brailleChar to display
	 */
	public void setBrailleChar(BrailleChar brailleChar) {
		this.brailleChar = brailleChar;
		touchedButtons.clear();
	}

	/**
	 * 
	 * @return The currently displaying brailleChar
	 */
	public BrailleChar getBrailleChar() {
		return brailleChar;
	}
}
